﻿/**
 * File:   range_rule_widget.c
 * Author: 
 * Brief:  
 *
 * Copyright (c) 2024 - 2024 
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2024-10-19  created
 *
 */


#include "tkc/mem.h"
#include "tkc/utils.h"
#include "base/canvas.h"
#include "base/vgcanvas.h"
#include "base/widget_vtable.h"
#include "base/style.h"
#include "tkc/color.h"
#include "tkc/rect.h"
#include "range_rule_widget.h"



static ret_t range_rule_widget_get_prop(widget_t* widget, const char* name, value_t* v) {
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  return_value_if_fail(range_rule_widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
  if(tk_str_eq(name, WIDGET_PROP_MAX_DEPTH)){
    value_set_int16(v, range_rule_widget->max_depth);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_SCALE_NUMS)){
    value_set_int(v, range_rule_widget->scale_nums);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_OFFSET)){
    value_set_int(v, range_rule_widget->offset);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_IS_HORIZIONAL)){
    value_set_bool(v, range_rule_widget->is_horizonal);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_IS_NUM_REVERSE)){
    value_set_bool(v, range_rule_widget->is_num_reverse);
    return RET_OK;
  }


  return RET_NOT_FOUND;
}

static ret_t range_rule_widget_set_prop(widget_t* widget, const char* name, const value_t* v) {
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
  if(tk_str_eq(name, WIDGET_PROP_MAX_DEPTH)){
    range_rule_widget->max_depth = value_int(v);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_SCALE_NUMS)){
    range_rule_widget->scale_nums = value_int(v);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_OFFSET)){
    range_rule_widget->offset = value_int(v);
    return RET_OK;
  }
  else if(tk_str_eq(name, WIDGET_PROP_IS_HORIZIONAL)){
    range_rule_widget->is_horizonal = value_bool(v);
    return RET_OK; 
  }
  else if(tk_str_eq(name, WIDGET_PROP_IS_NUM_REVERSE)){
    range_rule_widget->is_num_reverse = value_bool(v);
    return RET_OK;
  }
  return RET_NOT_FOUND;
}

static ret_t range_rule_widget_on_destroy(widget_t* widget) {
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  return_value_if_fail(widget != NULL && range_rule_widget != NULL, RET_BAD_PARAMS);



  return RET_OK;
}

static ret_t range_rule_draw_base_line(widget_t* widget, canvas_t* c){
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  style_t *style = widget->astyle;
  int stroke_width = style_get_int(style, STYLE_ID_BORDER_WIDTH, 2);
  color_t color = style_get_color(style, STYLE_ID_BORDER_COLOR, color_init(255, 0, 0, 255));

  vgcanvas_t *vg = canvas_get_vgcanvas(c);
  vgcanvas_set_line_width(vg, stroke_width);
  vgcanvas_set_stroke_color(vg, color);
  vgcanvas_save(vg);
  if(range_rule_widget->is_horizonal){
    vgcanvas_translate(vg, c->ox, c->oy - stroke_width / 2);
    vgcanvas_move_to(vg, 0, widget->h);
    vgcanvas_line_to(vg, widget->w, widget->h);
  }
  else{
    vgcanvas_translate(vg, c->ox - stroke_width / 2, c->oy);
    vgcanvas_move_to(vg, widget->w, 0);
    vgcanvas_line_to(vg, widget->w, widget->h);
  }
  vgcanvas_stroke(vg);
  vgcanvas_restore(vg);
  return RET_OK;
}




static ret_t range_rule_draw_scale(widget_t *widget, canvas_t* c, int nums){
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  style_t *style = widget->astyle;
  int stroke_width = style_get_int(style, STYLE_ID_BORDER_WIDTH, 2);
  color_t color = style_get_color(style, STYLE_ID_BORDER_COLOR, color_init(255, 0, 0, 255));

  int label_width = 25, label_height = 20;
  int label_area_w = widget->w - label_width;
  int label_area_h = widget->h - label_height; 

  vgcanvas_t *vg = canvas_get_vgcanvas(c);
  vgcanvas_set_line_width(vg, stroke_width);
  vgcanvas_set_stroke_color(vg, color);
  vgcanvas_save(vg);
  if(range_rule_widget->is_horizonal){
    vgcanvas_translate(vg, c->ox + stroke_width / 2, c->oy);
    for(int i = 0; i < nums; i++){
      vgcanvas_move_to(vg, i * label_area_w / (nums - 1) + label_width / 2, 0);
      vgcanvas_line_to(vg, i * label_area_w / (nums - 1) + label_width / 2, widget->h);
    }
  }
  else{
    vgcanvas_translate(vg, c->ox, c->oy + stroke_width / 2);
    for(int i = 0; i < nums; i++){
      vgcanvas_move_to(vg, 0, i * label_area_h / (nums - 1) + label_height / 2);
      vgcanvas_line_to(vg, widget->w, i * label_area_h / (nums - 1) + label_height / 2);
    }
  }

  vgcanvas_stroke(vg);
  vgcanvas_restore(vg);
  return RET_OK;
}




static ret_t range_rule_draw_numbers(widget_t *widget, canvas_t* c, int nums){
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  style_t *style = widget->astyle;
  char text[4] = {0};
  int font_size = style_get_int(style, STYLE_ID_FONT_SIZE, 18);
  wstr_t wstr;
  wstr_init(&wstr, 4);

  int label_width = 25, label_height = 20;
  int label_area_w = widget->w - label_width;
  int label_area_h = widget->h - label_height; 
  
  // rect setting
  canvas_set_fill_color(c, color_init(0, 0, 0, 255));

  // font setting
  canvas_set_font(c, "default", font_size);
  canvas_set_text_color(c, color_init(255, 255, 255, 255));
  canvas_set_text_align(c, ALIGN_H_CENTER, ALIGN_V_MIDDLE);
  
  if(range_rule_widget->is_horizonal){
    for(int i = 0; i < nums; i++){
      canvas_fill_rect(c, i * label_area_w / (nums - 1), 0, label_width, label_height);
      int num_text = (!range_rule_widget->is_num_reverse) ? i * range_rule_widget->max_depth / (nums - 1) : (nums - i - 1) * range_rule_widget->max_depth / (nums - 1);

      // Note: vgcanvas和canvas混用可能导致部分元素（如文本）无法显示的bug
      wstr_from_int(&wstr, num_text);
      rect_t r = rect_init(i * label_area_w / (nums - 1), 0, label_width, label_height);
      canvas_draw_text_in_rect(c, wstr.str, wstr.size, &r);
    }
  }
  else{
    for(int i = 0; i < nums; i++){
      canvas_fill_rect(c, 0, i * label_area_h / (nums - 1), label_width, label_height);
      int num_text = (!range_rule_widget->is_num_reverse) ? i * range_rule_widget->max_depth / (nums - 1) : (nums - i - 1) * range_rule_widget->max_depth / (nums - 1);
      wstr_from_int(&wstr, num_text);
      rect_t r = rect_init(0, i * label_area_h / (nums - 1), label_width, label_height);
      canvas_draw_text_in_rect(c, wstr.str, wstr.size, &r);
    }
  }

  wstr_reset(&wstr);
  return RET_OK;
}

static ret_t range_rule_widget_on_paint_self(widget_t* widget, canvas_t* c) {
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  range_rule_draw_base_line(widget, c);
  range_rule_draw_scale(widget, c, range_rule_widget->scale_nums);
  range_rule_draw_numbers(widget, c, range_rule_widget->scale_nums);
  return RET_OK;  
}

static ret_t range_rule_widget_on_event(widget_t* widget, event_t* e) {
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  return_value_if_fail(widget != NULL && range_rule_widget != NULL, RET_BAD_PARAMS);

  (void)range_rule_widget;

  return RET_OK;
}

const char* s_range_rule_widget_properties[] = {
  NULL
};

TK_DECL_VTABLE(range_rule_widget) = {.size = sizeof(range_rule_widget_t),
                          .type = WIDGET_TYPE_RANGE_RULE_WIDGET,
                          .clone_properties = s_range_rule_widget_properties,
                          .persistent_properties = s_range_rule_widget_properties,
                          .parent = TK_PARENT_VTABLE(widget),
                          .create = range_rule_widget_create,
                          .on_paint_border = widget_on_paint_null,
                          .on_paint_background = widget_on_paint_null,
                          .on_paint_self = range_rule_widget_on_paint_self,
                          .set_prop = range_rule_widget_set_prop,
                          .get_prop = range_rule_widget_get_prop,
                          .on_event = range_rule_widget_on_event,
                          .on_destroy = range_rule_widget_on_destroy};

widget_t* range_rule_widget_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) {
  widget_t* widget = widget_create(parent, TK_REF_VTABLE(range_rule_widget), x, y, w, h);
  range_rule_widget_t* range_rule_widget = RANGE_RULE_WIDGET(widget);
  return_value_if_fail(range_rule_widget != NULL, NULL);

  range_rule_widget->scale_nums = 6;
  range_rule_widget->max_depth = 20;
  return widget;
}

widget_t* range_rule_widget_cast(widget_t* widget) {
  return_value_if_fail(WIDGET_IS_INSTANCE_OF(widget, range_rule_widget), NULL);

  return widget;
}
